//-----------------------------------------------------------------------------
//
// @file	Mesh.h
// @brief	Mesh include files, variables and classes
// @author	Vinod Melapudi
// @date	20Feb2010
//
//-----------------------------------------------------------------------------

#ifndef _MESH_H
#define _MESH_H

// Common header
#include <vector>
#include "Vector.h"
#include "Color.h"


using namespace std;

typedef unsigned int uint;



// Mesh class to hold vertices, faces, normals, edge representation (HalfEdge structure), mesh rendering
class Mesh
{
public:
	enum RENDER_MODE
	{
		RENDER_MODE_DEFAULT,
		RENDER_MODE_WIREFRAME
	};

	enum POLYGON_MODE
	{
		POLYGON_MODE_TRIANGLE,
		POLYGON_MODE_QUAD
	};

	enum RENDER_METHOD
	{
		RENDER_METHOD_IMMEDIATE,
		RENDER_METHOD_VERTEX_ARRAYS,
		RENDER_METHOD_VERTEX_BUFFER_OBJECT
	};

public:

	Mesh();
	~Mesh();

	// Accessors
	inline	uint	GetNumVerticesPerFace()		{	return m_polygon_mode == POLYGON_MODE_TRIANGLE ? 3 : 4;		}
	inline	uint	GetNumFaces()				{	return m_face_vtx_indices.size() / GetNumVerticesPerFace();		}


	// Generate half edge representation from m_face_vtx_indices & m_vtx_positions
	void	GenerateHalfEdgeRep();

	// Generate normals of vertices using face info
	// flip : flips the normals
	void	GenerateNormals( bool flip );

	// Render mesh
	void	Render( uint max_faces_to_render = -1 );

	// Reset the polygons
	void	Reset();


private:
	// Rendering methods
	void RenderInImmediateMode( uint max_faces_to_render = -1 );
	void RenderUsingVertexArrays( uint max_faces_to_render = -1 );
	void RenderUsingVertexBufferObject( uint max_faces_to_render = -1 );



public:
	
	// Vertex arrays in seperate arrays, so it can be passed through vertex/normal pointers
	vector<Vector3>			m_vtx_positions;		// Vertex	positions
	vector<Vector3>			m_vtx_normals;			//			normals
	vector<Vector2>			m_vtx_texcoords;		//			tex coords
	vector<Color<float>>	m_vtx_colors;			//			colors

	vector<uint>			m_face_vtx_indices;		// Face indices (should have 3 indices per face)


	// Render params
	bool					m_visible;
	RENDER_MODE				m_render_mode;
	POLYGON_MODE			m_polygon_mode;
	RENDER_METHOD			m_render_method;

	
	// Vertex buffer object ids
	uint					m_vbo_position;
	uint					m_vbo_normal;
	uint					m_vbo_texcoord;
	uint					m_vbo_color;

public:

	// Half edge representation
	// http://www.flipcode.com/archives/The_Half-Edge_Data_Structure.shtml
	struct HalfEdgeRep
	{
		HalfEdgeRep()		{}
		~HalfEdgeRep()		{}

		struct Edge
		{
			uint	f;		// Face
			uint	v;		// The vertex where this edge ends (destination vertex)
			uint	ne;		// Next edge on same face (counter-clockwise)
			uint	pe;		// Prev edge on same face (counter-clockwise)
			uint	oe;		// Opposite edge (edge on opposite face)

			bool	unique_edge;	// Signifies this is the primary edge (and may have a pair edge) (used to render edges once between 2 vertices)

			Edge( uint _f, uint _v, uint _ne, uint _pe, uint _oe=-1 ) : f(_f), v(_v), ne(_ne), pe(_pe), oe(_oe), unique_edge(true)
			{}
		};

		vector<uint>		vertices;	// 1 Edge index emanating from vtx	: vertex index matches Mesh::m_vtx_positions
		vector<uint>		faces;		// 1 Edge index bordering the face	: face index matches Mesh::m_face_vtx_indices
		vector<Edge>		edges;

		// Find Faces at given vertex
		void	FindFacesFromVertex( uint vidx, vector<uint>& findices );
	};

	HalfEdgeRep*		m_half_edge_rep;
};

#endif
